{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Illustrates how to program the trigger:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Connect:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import phywhisperer.usb as pw\n",
    "phy = pw.Usb()\n",
    "phy.con(program_fpga=True)\n",
    "phy.set_power_source(\"host\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Power-off target to allow PhyWhisperer to autodetect its speed:\n",
    "Ensure the target device is connected to the PhyWhisperer.\n",
    "We'll turn off the target's power so that the PhyWhisperer can be programmed before turning the target back on. We do this because we'll be capturing what the target does when it's first turned on."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import time\n",
    "phy.set_power_source(\"off\")\n",
    "time.sleep(0.5)\n",
    "phy.reset_fpga()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### (Optionally) Manually set USB speed:\n",
    "By default, PhyWhisperer will auto-detect the target's USB speed when the target is connected or powered-up, so this should not be necessary."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "phy.set_usb_mode('auto')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Program trigger parameters:\n",
    "Here we enable the output trigger pulse, we set the number of pulses that are issued, and we set the width and delay parameters of each pulse.\n",
    "\n",
    "In this example we program PhyWhisperer to issue 2 trigger pulses after a pattern match:\n",
    "- the first pulse is immediately after the pattern match and 2 cycles wide;\n",
    "- the second pulse is 10 cycles after the first pulse and 4 cycles wide.\n",
    "\n",
    "(See `help(phy.set_trigger)` for more examples.)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "phy.set_trigger(num_triggers=2, delays=[0,10], widths=[2,4])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Arm the PhyWhisperer:\n",
    "You should see the blue ARM LED turn on to reflect the armed status."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "phy.arm()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Program the pattern match:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "phy.set_pattern(pattern=[0x2d, 0x00], mask=[0xff, 0xff])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Tell PhyWhisperer how many events to capture:\n",
    "Maximum is 8188."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "phy.set_capture_size(500)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Power up the target:\n",
    "Now that PhyWhisperer is programmed, power up the target. PW should auto-detect the correct speed, then the trigger should occur immediately.\n",
    "The trigger can be observed on the IO4 pin of the ChipWhisperer connector and on the \"Trig Out\" MCX connector."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "phy.set_power_source(\"host\")\n",
    "#Let device enumerate\n",
    "time.sleep(1.0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Ensure correct USB speed was detected:\n",
    "If the assertion fails, try setting the USB speed manually with set_usb_mode()."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "assert (phy.get_usb_mode() == 'FS')\n",
    "#assert (phy.get_usb_mode() == 'LS')\n",
    "#assert (phy.get_usb_mode() == 'HS')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Read what was captured:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "raw = phy.read_capture_data()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Interpret the captured data:\n",
    "The pattern match byte which triggered the captured isn't recorded; let's add it back it so that the USB data can be properly interpreted.\n",
    "Then, split the raw data into packets, and print them:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "phy.addpattern = True\n",
    "packets = phy.split_packets(raw)\n",
    "phy.print_packets(packets)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Iterate and generate a trigger pulse of increasing width:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import time\n",
    "start_time = time.time()\n",
    "for i in range (16):\n",
    "    print(\"Iteration %d: \" % i, end='')\n",
    "    # toggle target power on and off:\n",
    "    phy.set_power_source(\"off\")\n",
    "    time.sleep(0.1)\n",
    "    # set trigger parameters:\n",
    "    phy.set_trigger(delays=[0], widths=[2**i])\n",
    "    # arm:\n",
    "    phy.arm()\n",
    "    phy.set_power_source(\"host\")    \n",
    "    phy.wait_disarmed()\n",
    "    print(\"done\")\n",
    "    time.sleep(0.1)\n",
    "print(\"Elapsed time: %d seconds\" % (time.time()-start_time))   "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Capture and trigger delays are independent:\n",
    "When the trigger delay is set with `set_trigger(delays=[X])`, a capture delay is automatically set to match the first trigger delay (i.e. the capture will start when the first trigger pulse is issued).\n",
    "\n",
    "It's also possible to set the capture delay independently of the trigger delay with `set_capture_delay()`. Just remember that because `set_trigger()` sets a matched capture delay, `set_capture_delay()` must be called after, otherwise the capture delay will get overwritten.\n",
    "\n",
    "Here's a simple example which compares the data received with a capture delays of 0 and 200 clock cycles. YMMV but with an FS target, I observe that the delayed capture data starts 3 data bytes later:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "datatimes = [[], []]\n",
    "databytes = [[], []]\n",
    "stattimes = [[], []]\n",
    "statbytes = [[], []]\n",
    "for capture_delay in (0,1):\n",
    "    # toggle target power on and off:\n",
    "    phy.set_power_source(\"off\")\n",
    "    time.sleep(0.1)\n",
    "    # set trigger parameters:\n",
    "    phy.set_trigger(delays=[phy.ms_trigger(4)], widths=[1])\n",
    "    if capture_delay == 0:\n",
    "        phy.set_capture_delay(0)\n",
    "    else:\n",
    "        phy.set_capture_delay(200)\n",
    "    # arm:\n",
    "    phy.arm()\n",
    "    phy.set_power_source(\"host\")    \n",
    "    phy.wait_disarmed()\n",
    "    time.sleep(0.1)\n",
    "    raw = phy.read_capture_data()\n",
    "    phy.addpattern = False\n",
    "    datatimes[capture_delay], databytes[capture_delay], stattimes[capture_delay], statbytes[capture_delay] = phy.split_data(raw)\n",
    "\n",
    "print(\"Immediata capture data    Delayed capture data\")\n",
    "for i in range(10):\n",
    "    print(\"%4s                      %4s\" % (hex(databytes[0][i]), hex(databytes[1][i])))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "phy.close()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
